
#include <cstdio>
#include <BRender>
#include <BPainter>
#include <BScene>
#include <BShape>
#include <BViewer>
#include <BMouseEvent>

#include "MainHandler.h"

MainHandler::MainHandler()
{
	_shapeBoxVisible = true;
	_frustumVisible = true;
	_frustumSpaceVisible = true;

	_frustumPoints = new BVectorArray(8);
	_enableLights = new BLightArray();
	_visualNodes = new BNodeArray();
	_shapeQueue = new BMap<BShape*, BBox>();
	_transShapeQueue = new BMap<BShape*, BBox>();
	_constSceneItems = new ConstSceneTreeItemArray();

	connect("line-changed", &MainHandler::slotLineChanged);
}
MainHandler::~MainHandler()
{

}

void MainHandler::setTargetCamera(BCamera* camera)
{
	if (_targetCamera != camera)
	{
		if (_targetCamera)
			disconnect(_targetCamera);
		_targetCamera = camera;
		if (_targetCamera)
			connect(_targetCamera, Signal_Fresh, &MainHandler::slotTargetCameraFresh);
	}
}
void MainHandler::setTargetScene(BScene* scene)
{
	if (_targetScene != scene)
	{
		if (_targetScene)
			disconnect(_targetScene);
		_targetScene = scene;
		if (_targetScene)
			connect(_targetScene, Signal_Optimized, &MainHandler::slotTargetSceneOptimizedChanged);
	}
}
void MainHandler::setShapeBoxVisible(bool shapeBoxVisible)
{
	_shapeBoxVisible = shapeBoxVisible;
	this->fresh();
}
void MainHandler::setFrustumVisible(bool frustumVisible)
{
	_frustumVisible = frustumVisible;
	this->fresh();
}
void MainHandler::setFrustumSpaceVisible(bool frustumSpaceVisible)
{
	_frustumSpaceVisible = frustumSpaceVisible;
	this->fresh();
}

void MainHandler::slotTargetCameraFresh()
{
	this->fresh();
}
void MainHandler::slotTargetSceneOptimizedChanged()
{
	if (_constSceneItems->size())
	{
		_constSceneItems->clear();
		this->fresh();
	}
}
void MainHandler::slotLineChanged(BObject* object, const BValue& value)
{
	_line = value;
	this->fresh();
}

void MainHandler::paint(BPainter& painter)
{

}
void MainHandler::render(BRender& render)
{
	_targetCamera->query("frustum", _frustumPoints);
	_targetCamera->query("lights", _enableLights);
	_targetCamera->query("shapes", _shapeQueue);
	_targetCamera->query("shapes-transparent", _transShapeQueue);

	render.setLighting(false);
	render.setDepthTest(true);

	render.setColor(0, 255, 0);
	render.setLineWidth(3);
	render.drawLine(_line);

	if (_targetCamera)
	{
		BVector pos = _targetCamera->position();
		BVector center = _targetCamera->center();

		render.setColor(255, 255, 255);
		render.setLineWidth(3);
		render.drawLine(pos, center);
	}

	if (_frustumVisible)
	{
		BVector* vs = _frustumPoints->data();
		render.setColor(255, 0, 0, 200);
		render.fillQuad(vs[0], vs[1], vs[2], vs[3]);
		render.fillQuad(vs[4], vs[5], vs[6], vs[7]);
		render.setColor(255, 255, 0, 200);
		render.fillQuad(vs[0], vs[1], vs[5], vs[4]);
		render.fillQuad(vs[2], vs[3], vs[7], vs[6]);
	}

	if (_frustumSpaceVisible)
	{
		BSpace frustumSpace(_frustumPoints->first());
		for (int i = 1; i < _frustumPoints->size(); i++)
		{
			frustumSpace.expand(_frustumPoints->at(i));
		}
		render.setColor(255, 255, 255);
		render.drawSpace(frustumSpace);
	}

	if (_shapeBoxVisible)
	{
		render.setLineWidth(1);
		render.setCullback(false);
		render.setColor(255, 255, 255);
		for (auto it = _shapeQueue->begin(); it.valid(); it++)
		{
			BShape* shape = it.key();
			render.drawBox(it.value());
		}
		render.setColor(0, 255, 255);
		for (auto it = _transShapeQueue->begin(); it.valid(); it++)
		{
			BShape* shape = it.key();
			render.drawBox(it.value());
		}
	}

	if (_targetScene->optimized())
	{
		_targetCamera->query("scene-items", _constSceneItems);
		render.setLineSmooth(true);
		render.setLineWidth(1);
		render.setColor(255, 0, 255);
		for (int i = 0; i < _constSceneItems->size(); i++)
		{
			SceneTreeConstItem& item = _constSceneItems->at(i);
			render.drawSpace(item.space());
		}
	}
}

void MainHandler::slotAttached()
{

}
void MainHandler::slotDetached()
{

}

bool MainHandler::mousePressEvent(const BMouseEvent& mouseEvent)
{
	return BSphereHandler::mousePressEvent(mouseEvent);
}
bool MainHandler::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	return BSphereHandler::mouseReleaseEvent(mouseEvent);
}
bool MainHandler::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	return BSphereHandler::mouseMoveEvent(mouseEvent);
}


